﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Threading;

namespace iPdf
{


    public struct ActionReport
    {
        public int DoneItemsCount;
        public int UndoneItemsCount;
        public int ErrorItemsCount;
    }
    
    public abstract class Actor<ItemType, OptionType>: VirtualActor
    {
        #region Fields
        protected OptionType pageOption;
        protected ItemType workItem;
        #endregion

        #region Ctor
        protected Actor()
            :base()
        {
            worker.DoWork += new DoWorkEventHandler(DoWork);
        }
        #endregion

        #region Methods
        private void DoWork(Object sender, DoWorkEventArgs e)
        {
            Thread.CurrentThread.Priority = ThreadPriority.Lowest;
            ItemType[] items = (ItemType[])e.Argument;
            int itemCount = items.Length;
            try
            {
                Prepare();
            }
            catch (ActionCancelled)
            {
                NotPrepared(itemCount);
                return;
            }
            catch (TataException tataEx)
            {
                Global.MainWindow.ShowError(tataEx);
                NotPrepared(itemCount);
                return;
            }
            catch (Exception ex)
            {
                Global.MainWindow.ShowError(new TataException(ex.Message));
                NotPrepared(itemCount);
                return;
            }

            ActionReport report = new ActionReport();

            report.UndoneItemsCount = items.Length;
            report.DoneItemsCount = report.ErrorItemsCount = 0;

            ItemStatus curItemStatus;
            int curItemIndex = 1;
            foreach (ItemType item in items)
            {
                if (MainForm.ActionCancelled)
                {
                    break;
                }

                StartItem(curItemIndex);

                TataException exception = null;
                try
                {
                    workItem = item;
                    Work();
                    report.DoneItemsCount++;
                    curItemStatus = ItemStatus.Done;
                }
                catch (TataException ex)
                {
                    report.ErrorItemsCount++;
                    curItemStatus = ItemStatus.Error;
                    exception = ex;
                }
                catch (Exception ex)
                {
                    report.ErrorItemsCount++;
                    curItemStatus = ItemStatus.Error;
                    exception = new TataException(ex.Message);
                }
                
                --report.UndoneItemsCount;
                FinishItem(curItemIndex, curItemStatus, exception);

                ++curItemIndex;
            }

            try
            {
                Finish();
            }
            catch(Exception ex)
            {
                Global.MainWindow.ShowError(new TataException(ex.Message));
            }
            finally
            {
                FinishAllItems(report);
            }
        }


        public void Execute(ItemType[] items, OptionType opt)
        {
            pageOption = opt;

            worker.RunWorkerAsync(items);
        }

        #endregion
    }
}
